package com.anteater.eattheant.view;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;

import javax.microedition.khronos.opengles.GL10;

public class Mesh {

	private FloatBuffer verticesBuffer;
	private ShortBuffer indicesBuffer;
	private FloatBuffer textureBuffer;
	private int texture;
	
	// Flat Color
	private float[] rgba = { 1.0f, 1.0f, 1.0f, 1.0f };

	// Smooth Colors
	private FloatBuffer colorBuffer;

	public void draw(GL10 gl) {
		// Counter-clockwise winding.
		gl.glFrontFace(GL10.GL_CCW);

		// Enable face culling.
		gl.glEnable(GL10.GL_CULL_FACE);

		// What faces to remove with the face culling.
		gl.glCullFace(GL10.GL_BACK);

		// Enabled the vertices buffer to be used during rendering.
		gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);

		// Point out the where the vertex buffer is.
		gl.glVertexPointer(3, GL10.GL_FLOAT, 0, verticesBuffer);

		// Set flat color
		gl.glColor4f(rgba[0], rgba[1], rgba[2], rgba[3]);
		
		// Smooth color
		if (colorBuffer != null) {
			// Enable the color buffer to be used during rendering.
			gl.glEnableClientState(GL10.GL_COLOR_ARRAY);

			// Point out the where the color buffer is.
			gl.glColorPointer(4, GL10.GL_FLOAT, 0, colorBuffer);
		}
		
		// Textures
		if (this.textureBuffer != null) {
			// Enable alpha textures
			gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
			gl.glEnable(GL10.GL_BLEND);
			
			// bind the previously generated texture
			gl.glBindTexture(GL10.GL_TEXTURE_2D, texture);
			
			// Enabled the texture buffer to be used during rendering.
			gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
			
			// Point out the where the texture buffer is.
			gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);
		}

		if (indicesBuffer != null) {
			gl.glDrawElements(GL10.GL_TRIANGLES, indicesBuffer.capacity(),
					GL10.GL_UNSIGNED_SHORT, indicesBuffer);
		} else {
			gl.glDrawArrays(GL10.GL_TRIANGLE_FAN, 0,
					verticesBuffer.capacity() / 3);
		}

		// Disable the vertices buffer.
		gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);

		if (colorBuffer != null) {
			// Disable the color buffer.
			gl.glDisableClientState(GL10.GL_COLOR_ARRAY);
		}

		if (textureBuffer != null) {
			// Disable the texture buffer.
			gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
			
			// Disable alpha textures
			gl.glBlendFunc(GL10.GL_ONE, GL10.GL_ZERO);
			gl.glDisable(GL10.GL_BLEND);
		}
		
		// Disable face culling.
		gl.glDisable(GL10.GL_CULL_FACE);
	}

	protected void setVertices(float[] vertices) {
		ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
		vbb.order(ByteOrder.nativeOrder());
		verticesBuffer = vbb.asFloatBuffer();
		verticesBuffer.put(vertices);
		verticesBuffer.position(0);
	}

	protected void setIndices(short[] indices) {
		ByteBuffer ibb = ByteBuffer.allocateDirect(indices.length * 2);
		ibb.order(ByteOrder.nativeOrder());
		indicesBuffer = ibb.asShortBuffer();
		indicesBuffer.put(indices);
		indicesBuffer.position(0);
	}
	
	protected void setColor(float red, float green, float blue, float alpha) {
		// Setting the flat color.
		rgba[0] = red;
		rgba[1] = green;
		rgba[2] = blue;
		rgba[3] = alpha;
	}

	protected void setColors(float[] colors) {
		// float has 4 bytes.
		ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length * 4);
		cbb.order(ByteOrder.nativeOrder());
		colorBuffer = cbb.asFloatBuffer();
		colorBuffer.put(colors);
		colorBuffer.position(0);
	}
	
	protected void setTexture(float[] vertices, int texture) {
		ByteBuffer tbb = ByteBuffer.allocateDirect(vertices.length * 4);
		tbb.order(ByteOrder.nativeOrder());
		textureBuffer = tbb.asFloatBuffer();
		textureBuffer.put(vertices);
		textureBuffer.position(0);
		this.texture = texture;
	}
}
